package io.renren.modules.avanotes.component;

import io.renren.common.exception.BizCodeEnum;
import io.renren.common.exception.RRException;
import io.renren.config.BizConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author: xiaomi
 * @date: 2022/1/30
 * @description:
 */
@ConfigurationProperties(prefix = "ffmpeg")
@Component
@Slf4j
public class FfmpegComponent {

    /**
     * ffmpeg 启动路径
     */
    String ffmpegStartPath = "D:\\Tool\\VideoTrans\\ffmpeg-4.1.3-win64-static\\bin\\ffmpeg.exe";

    @Autowired
    @Qualifier(BizConfig.POOL_FFMPEG)
    ThreadPoolExecutor ffmpegPool;

    public void executeExtractMedia(String begin, String duration, String filePath, String targetPath) {
        File targetFile = new File(targetPath);
        if (targetFile.exists()) {
            log.info("文件已经存在，不进行转换！{}", targetPath);
            return;
        }
        ProcessBuilder builder = new ProcessBuilder();
        builder.redirectErrorStream(true);
        //1.command
        List<String> commandList = getExtractCommandList(begin, duration, filePath, targetPath);
        String completeCommand = StringUtils.join(commandList.toArray(), " ");
        log.info("execute command:{}", completeCommand);
        builder.command(commandList);
        Process process = null;
        try {
            process = builder.start();
            log.info("process isAlive :" + process.isAlive());
            if (!process.isAlive()) {
                //说明启动异常
                throw new RRException(BizCodeEnum.FFMPEG_NOT_ALIVE.getMsg());
            }
            //是否木有异常输出
            boolean isSuc = processInput(process);
            //TODO:暂时最大10分钟
            process.waitFor(3, TimeUnit.MINUTES);


            if (targetFile.exists() && targetFile.length() > 0 && isSuc) {
                //如果文件存在并存在大小

            } else {
                throw new RRException(BizCodeEnum.FFMPEG_TARGET.getMsg());
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new RRException(BizCodeEnum.FFMPEG_IO.getMsg());
        } catch (InterruptedException e) {
            log.error(e.getMessage(), e);
            throw new RRException(BizCodeEnum.FFMPEG_INTERRUPT.getMsg());
        } catch (ExecutionException e) {
            log.error(e.getMessage(), e);
            throw new RRException(BizCodeEnum.FFMPEG_EXECUTE.getMsg());
        } finally {
            process.destroy();
        }
    }


    //region private
    private boolean processInput(Process process) throws ExecutionException, InterruptedException {
        CompletableFuture<Void> futurePrintLog = CompletableFuture.runAsync(() -> {
            try (BufferedReader br1 = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
                String line1 = null;
                ///br1 != null &&
                while ((line1 = br1.readLine()) != null) {
                    //debug就不会出现在logs中
                    log.debug(line1);
                }
            } catch (IOException e) {
                ///e.printStackTrace();
                log.error(e.getMessage(), e);
            } finally {
                ///close(is1,inputStreamReader, br1);
            }
        }, ffmpegPool);

        CompletableFuture<Boolean> futurePrintError = CompletableFuture.supplyAsync(() -> {
            boolean res = true;
            try (BufferedReader br1 = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
                String line1 = null;
                ///br1 != null &&
                while ((line1 = br1.readLine()) != null) {
                    //debug就不会出现在logs中
                    log.error(line1);
                    res = false;
                }
            } catch (IOException e) {
                ///e.printStackTrace();
                log.error(e.getMessage(), e);
            } finally {
                ///close(is1,inputStreamReader, br1);
            }
            return res;
        }, ffmpegPool);

        CompletableFuture<Void> future = CompletableFuture.allOf(futurePrintLog, futurePrintError);
        future.get();
        return futurePrintError.get();
    }
    //endregion

    /**
     * ffmpeg -ss (beginTime) -t (duration) -accurate_seek -i (source) -codec copy (target)
     *
     * @param begin
     * @param duration
     * @param filePath
     * @param targetPath
     * @return
     */
    private List<String> getExtractCommandList(String begin, String duration, String filePath, String targetPath) {
        List<String> list = new ArrayList<>();
        list.add(this.ffmpegStartPath);
        list.add("-ss");
        list.add(begin);
        list.add("-t");
        list.add(duration);
        list.add("-accurate_seek");
        list.add("-i");
        list.add(filePath);
        list.add("-codec");
        list.add("copy");
        list.add(targetPath);
        return list;
    }
}
